#include <stdio.h>
#include <getopt.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>



#include "system_info.h"
#include "cpu_mem_tune.h"
#include "list/list.h"

void print_usage()
{
	printf("Usage: [-c x(0-100)] [-m x(0-100)]\n");
}

void do_arguments(limit_state *limit, int argc, char **argv)
{
    int i;
	
	if(argc <= 1){
		printf("Show CPU and MEM rate without any argument!\n");
		return;
	}

    /* this appears to keep getopt happy */
    optind = 1;
    while ((i = getopt(argc, argv, "c:m:")) != EOF)
    {
		switch(i)
		{
			case 'c':
				i = atoi(optarg);
				if((i > 100)&&(i < 0)){
					print_usage();
				}else{
					printf("Set CPU rate limit to %d%%\n",i);
					limit->cpu_limit = i;
				}
				break;


			case 'm':
			    i = atoi(optarg);
			    if((i > 100)&&(i < 0)){
					print_usage();
				}else{
					printf("Set MEM rate limit to %d%%\n",i);
					limit->mem_limit = i;
				}
			    break;

			default:
				print_usage();
				exit(-1);
		}
    }

}


void tune_cpu(int limit)
{
	pid_t fpid, del_pid;
	int retval,status;
	int cur_cpu_rate = get_user_cpu_rate();
	if(cur_cpu_rate < limit){
		fpid = fork();
		if(fpid < 0){
			printf("%s:[%d] ERROR:fork child.\n",__func__,__LINE__);
		}else if(fpid == 0){
			printf("Child:PID(%d)Running\n",getpid());
			while(1);
		}else{
			if(add_tail(fpid) < 0){
				printf("%s:[%d] ERROR:add child pid to list.\n",__func__,__LINE__);
			}
			printf("Father:PID(%d)Running\n",getpid());
		}
	
	}else if(cur_cpu_rate > (limit + 10)){
		if(is_empty()){
			return;
		}
		del_pid = get_del_tail();
		if(del_pid > 0){
			if ( 0 == (waitpid( del_pid, &status, WNOHANG )))
			{
				printf( "Father:killing PID(%d)\n", del_pid );
				retval = kill( del_pid,SIGKILL );

				if ( retval )
				{
					printf( "Father:kill PID(%d) failed\n", del_pid );					
				}
				else
				{
					printf("Father:KILL PID(%d) OK\n",del_pid);
				}
				waitpid( del_pid, &status, 0 );
			}
		}else{
			printf("%s:[%d] ERROR:list is empty.You cannot enter this line.\n",__func__,__LINE__);
		}
	}

}
#define MAX_MEM_BLK 2048
mem_block_t memblks[MAX_MEM_BLK];
int cur_memblk = 0;


void tune_mem(int limit)
{
	char *p_malloc;
	int cur_mem_rate = get_mem_rate();
	int total_mem = get_total_mem_size();
	if(cur_mem_rate < limit){
		if(cur_memblk >= MAX_MEM_BLK - 1){
			printf("%s:[%d] ERROR:oh no, cannot malloc more memory.\n",__func__,__LINE__);
		}else{
			p_malloc = malloc(total_mem/20);
			if(p_malloc != 0){
				memblks[cur_memblk].p_memblk = p_malloc;
				memblks[cur_memblk].size = total_mem/20;
				cur_memblk++;
				printf("%s:[%d] INFO:malloc memory %d.\n",__func__,__LINE__,cur_memblk - 1);
			}else{
				printf("%s:[%d] ERROR:get memory failure.\n",__func__,__LINE__);
			}
		}
	}else if(cur_mem_rate > limit + 10){
		if(cur_memblk <= 0){
			return;
		}else{
			cur_memblk--;
			free(memblks[cur_memblk].p_memblk);
			printf("%s:[%d] INFO:realse memory %d.\n",__func__,__LINE__,cur_memblk - 1);
		}
	}

}


int main(int argc, char **argv)
{
	limit_state limit;
	memset(&limit,0,sizeof(limit));
	do_arguments(&limit, argc, argv);

	init_list();
	
	while(1){
		//printf("CPU rate is %f\n",get_user_cpu_rate());
		//printf("Mem rate is %f\n",get_mem_rate());
		tune_cpu(limit.cpu_limit);
		tune_mem(limit.mem_limit);
	}
}